package com.echat.serviceapigateway.security.tool;

import com.echat.serviceapigateway.security.constant.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by xiaoyu on 2015/4/5.
 * 获得请求者IP，数字IP和字符串IP转换
 */
public class IPUtils {
    private static final Logger logger = LoggerFactory.getLogger(IPUtils.class);
    private static final String ipDot = ".";
    private static final String selfIP = "127.0.0.1";
    private static long[][] innerIPs = new long[3][2];//将3个A b c类地址的起始结束位置记录下来用来判断IP是否是内网IP

    static {
        //10.0.0.0-10.255.255.255
        //172.16.0.0-172.31.255.255
        //192.168.0.0-192.168.255.255
        innerIPs[0][0] = ipToLong("10.0.0.0");
        innerIPs[0][1] = ipToLong("10.255.255.255");
        innerIPs[1][0] = ipToLong("172.16.0.0");
        innerIPs[1][1] = ipToLong("172.31.255.255");
        innerIPs[2][0] = ipToLong("192.168.0.0");
        innerIPs[2][1] = ipToLong("192.168.255.255");
    }

    public static boolean isInnerIp(long ip) {
        return (innerIPs[0][0] <= ip && innerIPs[0][1] >= ip) || (innerIPs[1][0] <= ip && innerIPs[1][1] >= ip) || (innerIPs[2][0] <= ip && innerIPs[2][1] >= ip);
    }

    public static String[] PROXY_HEAD_TAGS = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_CLIENT_IP",
            "HTTP_X_FORWARDED_FOR",
            "ORIG_CLIENT_IP",
            "remote-Client-IP"
    };

    public static String longToIP(long ip) {
        StringBuffer rs = new StringBuffer();
        rs.append(String.valueOf(ip >>> 24));
        rs.append(ipDot);
        rs.append(String.valueOf((ip & 0x00FFFFFF) >>> 16));
        rs.append(ipDot);
        rs.append(String.valueOf((ip & 0x0000FFFF) >>> 8));
        rs.append(ipDot);
        rs.append(String.valueOf((ip & 0x000000FF)));
        return rs.toString();
    }

    /**
     * @param ipBytes
     * @return 根据byte数字获取ip的long值
     */
    public static long byteToLong(byte[] ipBytes) {
        if (ipBytes == null || ipBytes.length != 4) {
            long rs = 0;
            rs += (((int) (ipBytes[0] > 0 ? ipBytes[0] : (ipBytes[0] + 256))) << 24);
            rs += (((int) (ipBytes[1] > 0 ? ipBytes[1] : (ipBytes[1] + 256))) << 16);
            rs += (((int) (ipBytes[2] > 0 ? ipBytes[2] : (ipBytes[2] + 256))) << 8);
            rs += ((int) (ipBytes[3] > 0 ? ipBytes[3] : (ipBytes[3] + 256)));
        }
        return 0L;
    }

    /**
     * @return 根据byte数字获取ip的long值
     */
    public static byte[] longToByte(long ip) {
        byte[] ret = new byte[4];
        StringBuffer rs = new StringBuffer();
        ret[0] = (byte) ((ip >>> 24) & 0xFF);
        ret[1] = (byte) (((ip & 0x00FFFFFF) >>> 16) & 0xFF);
        ret[2] = (byte) (((ip & 0x0000FFFF) >>> 8) & 0xFF);
        ret[3] = (byte) ((ip & 0x000000FF) & 0xFF);
        return ret;
    }

    /**
     * @param ip 需要转换的字符串IP
     * @return 返回输入字符串IP的long型IP
     */
    public static long ipToLong(String ip) {
        if (StringUtils.isEmpty(ip)) {
            return -1L;
        }
        try {
            String[] ips = ip.split("\\.");
            long rs = 0;
            if (ips != null && ips.length == 4) {
                rs += (Long.parseLong(ips[0]) << 24);
                rs += (Long.parseLong(ips[1]) << 16);
                rs += (Long.parseLong(ips[2]) << 8);
                rs += Long.parseLong(ips[3]);
            }else{
                if(ips.equals("0:0:0:0:0:0:0:1")){
                    return ipToLong("127.0.0.1");
                }
            }
            return rs;
        } catch (Exception e) {
            return -1L;
        }

    }

    /**
     * @param request 客户端请求的request
     * @return 返回本次请求的来访IP
     */
    public static String getRequestIP(HttpServletRequest request) {
        if (hasProxy(request)) {
            String ip = null;
            boolean proxyHeadHasIp = false;
            for (int i = 0; i < PROXY_HEAD_TAGS.length; i++) {
                ip = request.getHeader(PROXY_HEAD_TAGS[i]);
                if (!isEmptyIp(ip)) {
                    if ("X-Forwarded-For".equalsIgnoreCase(PROXY_HEAD_TAGS[i])) {
                        String[] temp = ip.split(",");
                        ip = temp[0].trim();
                    }
                    proxyHeadHasIp = true;
                    break;
                }
            }
            if (StringUtils.isNotEmpty(ip)) {
                ip = ip.trim();
            }
            if (proxyHeadHasIp) {
                try {
                    if (isInnerIp(ipToLong(ip))) {
                        proxyHeadHasIp = false;
                        ip = null;
                    }
                } catch (Exception e) {
                    logger.error("check ip is innerIp error with ip:" + ip, e);
                }
            }
            if (!proxyHeadHasIp || StringUtils.isEmpty(ip)) {
                ip = request.getRemoteAddr().trim();
            }
            return ip;
        } else {
            return request.getRemoteAddr();
        }
    }

    public static long getRequestIpLong(HttpServletRequest request) {
        String reqIp = IPUtils.getRequestIP(request);
        if (StringUtils.isNotEmpty(reqIp)) {
            try {
                return IPUtils.ipToLong(reqIp.trim());
            } catch (Exception e) {
                logger.error("get request ip error!", e);
            }
        }
        return Constants.emptyIp;
    }

    public static boolean isEmptyIp(String ip) {
        return ip == null || ip.equals(Constants.EMPTY_STR) || ip.indexOf("u") != -1 || ip.equals(selfIP);
    }

    private static boolean hasProxy(HttpServletRequest request) {
        for (int i = 0; i < PROXY_HEAD_TAGS.length; i++) {
            if (request.getHeader(PROXY_HEAD_TAGS[i]) != null) {
                return true;
            }
        }
        return false;
    }


    public static void main(String[] s) {
        String ip = "127.0.0.1";

        System.out.println(ipToLong(ip));

        System.out.println(isInnerIp(ipToLong("10.81.4.95")));
    }
}
